package AnalisisSintactico;

import maquinaP.MaquinaP_impl;
import Traduccion_Semantica.TraductorLenguajeObjeto;
import utils.ComprobacionTipos;
import utils.EscribeTxt;
import utils.TablaSimbolos;
import utils.enumerados.*;
import utils.nodos.*;
import gui.MensajeError;

import AnalisisLexico.AnalizadorLexico_v2;
import AnalisisLexico.Token.*;

public class AnalizadorSintactico_v4{

	private TablaSimbolos tablaSymbol = null;
	private AnalizadorLexico_v2 analisisLEx;
	private Token tokenActual;
	private MensajeError errores = null;
	private PalabrasReservadasTipos palReservTipos = new PalabrasReservadasTipos();
	private TraductorLenguajeObjeto traductor;
	private boolean hayErrores =false;
	private boolean hayRetornoFuncion = false;
	private boolean estoyEnFuncion = false;
	private String nombreFuncion = null;
	private int nivel = 0;
	private int nivelH = 500;
	private String arch;
	/**
	 * 
	 * @param v Vector con todos los Token
	 */
	public AnalizadorSintactico_v4(String nomfich, String arch){
		traductor = new TraductorLenguajeObjeto();
		errores = new MensajeError();
		analisisLEx = new AnalizadorLexico_v2(nomfich);
		tablaSymbol = new TablaSimbolos();
		hayErrores =false;
		nivel = 0;
		this.arch = arch;
	}
	
	public AnalizadorLexico_v2 getAnalisisLEx(){
		return analisisLEx;
	}
	
	public TablaSimbolos getTablaSymbol() {
		return tablaSymbol;
	}
	
	public TraductorLenguajeObjeto getTraductor(){
		return traductor;
	}
	
	public MensajeError getErrores(){
		return errores;
	}
	
	public void analiza(TablaSimbolos t) throws Exception {
		tablaSymbol = t;
		PROG();	//Empezamos...
		if(!hayErrores){
			System.out.println("OK");
			tablaSymbol.muestraContenido();
			traductor.muestraCodigoObjeto();
			
			EscribeTxt e = new EscribeTxt(arch);
			StringBuffer b = new StringBuffer();
			for(int i = 0; i < traductor.obtenerCodigoObjeto().size();i++)
				b.append(traductor.obtenerCodigoObjeto().elementAt(i)+'\n');
			e.vuelcaFichero(b.toString());
			MaquinaP_impl m = new MaquinaP_impl(traductor.obtenerCodigoObjeto(),tablaSymbol.nivelMax());
			m.ejecuta();
		}
	}
	/**
	 * PROG -> LISTDECLAFUNC INSTRCOMP
	 * @throws Exception 
	 */
	private void PROG() throws Exception {
		tokenActual = analisisLEx.analiza();
		int incr = traductor.traduce("incrementa ");
		int ira = traductor.traduce("ir_a ");
		LISTDECLAFUNC();
		traductor.parchea("ir_a "+traductor.obtenerCodigoObjeto().size(), ira);
		INSTRCOMP();
		traductor.parchea("incrementa "+tablaSymbol.numReservaVar(nivel), incr);
	}
	
	/**
	 * LISTDECLAFUNC -> funcion IDECLAFUNCION LISTDECLAFUNC
	 * LISTDECLAFUNC -> procedimiento IDECLAPROCEDIMIENTO LISTDECLAFUNC
	 * LISTDECLAFUNC -> lambda
	 * @throws Exception 
	 */
	private void LISTDECLAFUNC() throws Exception {
		if(tokenActual.getLexema().equals("funcion")){
			tokenActual = analisisLEx.analiza();
			if(!tablaSymbol.estaToken(tokenActual.getLexema())){
				nivel++;
				tablaSymbol.meteToken(tokenActual.getLexema(),tokenActual.getIdentificador(),ClaseToken.FUNCION,ClaseTipos.ENT, nivel,traductor.obtenerCodigoObjeto().size());
				IDECLAFUNCION();
				nivel--;
				LISTDECLAFUNC();
			}
			else{
				if(!hayErrores)errores.addError("Error: Restriccion Contextual. Identificador ya usado - Linea: "+analisisLEx.getNumLinea());
				hayErrores = true;
			}
		}
		else if(tokenActual.getLexema().equals("procedimiento")){
			tokenActual = analisisLEx.analiza();
			if(!tablaSymbol.estaToken(tokenActual.getLexema())){
				nivel++;
				tablaSymbol.meteToken(tokenActual.getLexema(),tokenActual.getIdentificador(),ClaseToken.PROCEDIMIENTO,null, nivel,traductor.obtenerCodigoObjeto().size());
				IDECLAPROCEDIMIENTO();
				nivel--;
				LISTDECLAFUNC();
			}
			else{
				if(!hayErrores)errores.addError("Error: Restriccion Contextual. Identificador ya usado - Linea: "+analisisLEx.getNumLinea());
				hayErrores = true;
			}
		}
	}
	/**
	 * INSTRCOMP -> inicio LISTINSTR fin
	 * @throws Exception 
	 */
	private void INSTRCOMP() throws Exception {
		if(tokenActual.getLexema().equals("inicio")){
			tokenActual = analisisLEx.analiza();
			LISTINSTR();
			if(!tokenActual.getLexema().equals("fin")){
				if(!hayErrores)errores.addError("Error: Fallo de estructura. Falta fin instruccion - Linea: "+analisisLEx.getNumLinea());
				hayErrores = true;
			}
			else
				tokenActual = analisisLEx.analiza();
		}
		else{
			if(!hayErrores)errores.addError("Error: Fallo de estructura. Falta inicio instruccion - Linea: "+analisisLEx.getNumLinea());
			hayErrores = true;
		}
	}
	
	
	/**
	 * LISTINSTR -> INSTR LISTINSTR | lambda
	 * @throws Exception 
	 */
	private void LISTINSTR() throws Exception {		
		if((!tokenActual.getLexema().equals("fin"))){
			INSTR();
			LISTINSTR();
		}
		
	}
	
	/**
	 *INSTR-> DESCRIPT IASIGVAR
	 *INSTR-> IDECLAVAR
	 *INSTR-> tipo IDECLATIPO
	 *INSTR-> mientras IMIENTRAS
	 *INSTR-> si ISI
	 *INSTR->hacer IHACER
	 *INSTR-> nuevo INUEVO
	 *INSTR->writeln EXP
	 *INSTR-> identFuncion 
	 *INSTR-> identProcedimiento (ListParametros)
	 *INSTR->retorno EXP 
	 * @throws Exception 
	 */
	private void INSTR() throws Exception {
		//Si el token es un variable
		if(tablaSymbol.esVariable(tokenActual.getLexema())){
			//tokenActual = analisisLEx.analiza();
			INodoEstructura n1 = DESCRIPT();
			INodoEstructura n2 = IASIGVAR();
			if(n1 != null && n2 != null)
				if(!ComprobacionTipos.compruebaCompatibilidad(n1, n2)){
					if(!hayErrores)errores.addError("Error: Incompatibilidad de tipos - Linea: "+analisisLEx.getNumLinea());
					hayErrores = true;
				}
					
			traductor.traduce("desapila_ind");
		}
		else if(tablaSymbol.esFuncion(tokenActual.getLexema())){
			Token nomf = tokenActual;
			tokenActual = analisisLEx.analiza();
			if(tokenActual.getLexema().equals("(")){
				PASOPARAMETROS();
				//tokenActual = analisisLEx.analiza();
				if(!tokenActual.getLexema().equals(")")){
					if(!hayErrores)errores.addError("Error: Fallo de estructura. En la expresion - Linea: "+analisisLEx.getNumLinea());
					hayErrores = true;
				}
			traductor.traduce("incrementa 1");//+(tablaSymbol.dameEstructura(nomf.getLexema()).getOffset()+1));
			traductor.traduce("llama "+tablaSymbol.dirMemoriaToken(nomf)+" "+tablaSymbol.nivel(nomf.getLexema()));
			tokenActual = analisisLEx.analiza();
			}
		}
		//Si el token es un tipo basico
		else if(palReservTipos.esReservada(tokenActual.getLexema())){
			//	<tokenActual = analisisLEx.analiza();
			IDECLAVAR();
		}
		//Si el token es un tipo Puntero
		else if(tokenActual.getLexema().equals("@")){
			//	<tokenActual = analisisLEx.analiza();
			IDECLAVAR();
		}
		//Si el token es un tipo array
		else if(tokenActual.getLexema().equals("array")){
			//	<tokenActual = analisisLEx.analiza();
			IDECLAVAR();
		}
		//Si el token es un tipo Registro
		else if(tokenActual.getLexema().equals("registro")){
			IDECLAVAR();
		}
		//Si el token es un tipo de dato y declaramos una variable del mismo
		else if(tablaSymbol.esTipo(tokenActual.getLexema())){
			//tokenActual = analisisLEx.analiza();
			IDECLAVAR();
		}
		//Se a a declarar un tipo
		else if(tokenActual.getLexema().equals("tipo")){
			tokenActual = analisisLEx.analiza();
			IDECLATIPO();
		}
		//Va a haber una instruccion mientras
		else if(tokenActual.getLexema().equals("mientras")){
			tokenActual = analisisLEx.analiza();
			IMIENTRAS();
		}
		//Va a haber una instruccion si
		else if(tokenActual.getLexema().equals("si")){
			tokenActual = analisisLEx.analiza();
			ISI();
		}
		//Va a haber una instruccion hacer
		else if(tokenActual.getLexema().equals("hacer")){
			tokenActual = analisisLEx.analiza();
			IHACER();
		}
		//Se va a crear una variable que es un puntero
		else if(tokenActual.getLexema().equals("nuevo")){
			tokenActual = analisisLEx.analiza();
			INUEVO();
		}
		else if(tablaSymbol.esProcedimiento(tokenActual.getLexema())){
			Token nomf = tokenActual;
			tokenActual = analisisLEx.analiza();
			if(tokenActual.getLexema().equals("(")){
				PASOPARAMETROS();
				//tokenActual = analisisLEx.analiza();
				if(!tokenActual.getLexema().equals(")")){
					if(!hayErrores)errores.addError("Error: Fallo de estructura. En la expresion - Linea: "+analisisLEx.getNumLinea());
					hayErrores = true;
				}						
				traductor.traduce("llama "+tablaSymbol.dirMemoriaToken(nomf)+" "+tablaSymbol.nivel(nomf.getLexema()));
				tokenActual = analisisLEx.analiza();
			}
		}
		else if(tokenActual.getSubclase() == 1){ //PalabrasReservadasFunc
			Token tAux = tokenActual;
			tokenActual = analisisLEx.analiza();
			
			if(tAux.getLexema().equals("writeln")){
				EXP();
				traductor.traduce("escribe");
				traductor.traduce("desapila");
			}
			else if(tAux.getLexema().equals("retorno")){
				traductor.traduce("apila -1");//Resultado
				traductor.traduce("apila 1");//Nivel
				EXP();
				traductor.traduce("desapila_ind");
				traductor.traduce("retorno "+nivel);
				hayRetornoFuncion = true; 
			}
		}
		//Todas las instrucciones acaban en punto y coma
		if(!tokenActual.getLexema().equals(";")){
			if(!hayErrores)errores.addError("Error: Fallo de estructura instruccion. Falta el punto y coma - Linea: "+analisisLEx.getNumLinea());
			hayErrores = true;
		}	
		//cojo un nuevo token al final
		tokenActual = analisisLEx.analiza();
	}
	
	
	/**
	 * IDECLAFUNCION -> Identificador ( LISTPARAMETROS):TIPOCONSTRUIDO LISTDECLAFUNC INSTRCOMP
	 * @throws Exception 
	 */
	private void IDECLAFUNCION() throws Exception{
		if(tokenActual.getIdentificador() == 256){ //256=Identificador
			Token tokenFun = tokenActual;
			tokenActual = analisisLEx.analiza();
			if(tokenActual.getLexema().equals("(")){
				tokenActual = analisisLEx.analiza();
				NodoParametros nodPar = new NodoParametros();
				LISTPARAMETROS(nodPar);
				if(tokenActual.getLexema().equals(")")){
					tokenActual = analisisLEx.analiza();
					if(tokenActual.getLexema().equals(":")){
						tokenActual = analisisLEx.analiza();
						ClaseTipos c = TIPOCONSTRUIDO().getTipo();
						tablaSymbol.esblaceTipo(tokenFun.getLexema(), c);
						LISTDECLAFUNC();
						tablaSymbol.establecePosMem(tokenFun.getLexema(), traductor.obtenerCodigoObjeto().size());
						tablaSymbol.estableceEstructura(tokenFun.getLexema(), nodPar);
						hayRetornoFuncion = false;
						estoyEnFuncion = true;
						nombreFuncion = tokenFun.getLexema();
						INSTRCOMP();
						estoyEnFuncion = false;
						if(!hayRetornoFuncion){
							if(!hayErrores)errores.addError("Error: Fallo de estructura. Retorno funcion - Linea: "+analisisLEx.getNumLinea());
							hayErrores = true;
						}
					}
					else{
						if(!hayErrores)errores.addError("Error: Fallo de estructura. Declaracion funcion - Linea: "+analisisLEx.getNumLinea());
					hayErrores = true;
				}
				}
				else{
					if(!hayErrores)errores.addError("Error: Fallo de estructura. Declaracion funcion ( - Linea: "+analisisLEx.getNumLinea());
					hayErrores = true;
				}
			}
			else{
				if(!hayErrores)errores.addError("Error: Fallo de estructura. Declaracion funcion ) - Linea: "+analisisLEx.getNumLinea());
				hayErrores = true;
			}
		}
		else{
			if(!hayErrores)errores.addError("Error: Fallo de estructura. Declaracion nombre funcion - Linea: "+analisisLEx.getNumLinea());
			hayErrores = true;
		}
	}
	/**
	 * IDECLAPROCEDIMIENTO-> Identificador ( LISTPARAMETROS) LISTDECLAFUNC INSTRCOMP
	 * @throws Exception 
	 */
	private void IDECLAPROCEDIMIENTO() throws Exception{
		if(tokenActual.getIdentificador() == 256){ //256=Identificador
			Token tokenProc = tokenActual;
			tokenActual = analisisLEx.analiza();
			if(tokenActual.getLexema().equals("(")){
				tokenActual = analisisLEx.analiza();
				NodoParametros nodPar = new NodoParametros();
				LISTPARAMETROS(nodPar);
				if(tokenActual.getLexema().equals(")")){
					tokenActual = analisisLEx.analiza();
					LISTDECLAFUNC();
					tablaSymbol.establecePosMem(tokenProc.getLexema(), traductor.obtenerCodigoObjeto().size());
					tablaSymbol.estableceEstructura(tokenProc.getLexema(), nodPar);
					estoyEnFuncion = true;
					INSTRCOMP();
					estoyEnFuncion = false;
					traductor.traduce("retorno "+nivel);
				}
				else{
					if(!hayErrores)errores.addError("Error: Fallo de estructura. Declaracion procedimiento ( - Linea: "+analisisLEx.getNumLinea());
					hayErrores = true;
				}
			}
			else{
				if(!hayErrores)errores.addError("Error: Fallo de estructura. Declaracion procedimiento ) - Linea: "+analisisLEx.getNumLinea());
				hayErrores = true;
			}}
		else{
			if(!hayErrores)errores.addError("Error: Fallo de estructura. Declaracion nombre procedimiento - Linea: "+analisisLEx.getNumLinea());
			hayErrores = true;
		}
	}
	private void LISTPARAMETROS(INodoEstructura nodo) throws Exception {
		if(!tokenActual.getLexema().equals(")")){
			INodoEstructura nod = TIPOCONSTRUIDO();
			if(tokenActual.getIdentificador() == 256){
				nodo.anade(tokenActual.getLexema(), nod);
				tokenActual = analisisLEx.analiza();
				RLISTPARAMETROS(nodo);
			}
		}
		
	}
	private void RLISTPARAMETROS(INodoEstructura nodo) throws Exception{
		if(tokenActual.getLexema().equals(",")){
			tokenActual = analisisLEx.analiza();
			INodoEstructura nod = TIPOCONSTRUIDO();
			if(tokenActual.getIdentificador() == 256){
				nodo.anade(tokenActual.getLexema(), nod);
				tokenActual = analisisLEx.analiza();
				RLISTPARAMETROS(nodo);
			}
		}
	}
	private void PASOPARAMETROS() throws Exception {
		if(!tokenActual.getLexema().equals(")")){
			tokenActual = analisisLEx.analiza();
			EXP();
			RPASOPARAMETROS();
			
		}
	}
	private void RPASOPARAMETROS() throws Exception{
		if(tokenActual.getIdentificador() == 44){
			tokenActual = analisisLEx.analiza();
			EXP();
			RPASOPARAMETROS();
		}
	}
	/**
	 * INUEVO-->(Identificador)
	 * @throws Exception 
	 */
	private void INUEVO() throws Exception {
		if(tokenActual.getLexema().equals("(")){
			tokenActual = analisisLEx.analiza();
			if(tokenActual.getIdentificador() == 256 && tablaSymbol.estaToken(tokenActual.getLexema())){
				if(tablaSymbol.dameEstructura(tokenActual.getLexema()).getTipo() == ClaseTipos.PUNTERO){
					traductor.traduce("incrementaH "+tablaSymbol.dameEstructura(tokenActual.getLexema()).getOffset());
					traductor.traduce("apila "+tablaSymbol.dirMemoriaToken(tokenActual));
					traductor.traduce("apila "+tablaSymbol.nivel(tokenActual.getLexema()));
					traductor.traduce("apila "+(((NodoPuntero)tablaSymbol.dameEstructura(tokenActual.getLexema())).getTamano()+nivelH));
					nivelH = nivelH + ((NodoPuntero)tablaSymbol.dameEstructura(tokenActual.getLexema())).getTamano();
					traductor.traduce("desapila_ind");
					tokenActual = analisisLEx.analiza();	
				}
				if(tokenActual.getLexema().equals(")")){
					tokenActual = analisisLEx.analiza();
				}
				else{
					if(!hayErrores)errores.addError("Error: Fallo de estructura instruccion nuevo ) - Linea: "+analisisLEx.getNumLinea());
					hayErrores = true;
				}
			}
			else{
				if(!hayErrores)errores.addError("Error: Fallo de estructura instruccion nuevo ID - Linea: "+analisisLEx.getNumLinea());
				hayErrores = true;
			}
		}
		else{
			if(!hayErrores)errores.addError("Error: Fallo de estructura instruccion nuevo ( - Linea: "+analisisLEx.getNumLinea());
			hayErrores = true;
		}
		
	}
	
	/**
	 * IHACER->INSTRCOMP mientras (EXP)
	 * @throws Exception 
	 */
	private void IHACER() throws Exception {
		int ir_a = traductor.obtenerCodigoObjeto().size();
		INSTRCOMP();
		if(tokenActual.getLexema().equals("mientras")){
			tokenActual = analisisLEx.analiza();
			if(tokenActual.getLexema().equals("(")){
				tokenActual = analisisLEx.analiza();
				EXP();
				if(tokenActual.getLexema().equals(")")){
					traductor.traduce("ir_falso "+(traductor.obtenerCodigoObjeto().size()+2));
					traductor.traduce("ir_a "+ir_a);
					
					tokenActual = analisisLEx.analiza();
				}
				else{
					if(!hayErrores)errores.addError("Error: Fallo de estructura instruccion hacer ) - Linea: "+analisisLEx.getNumLinea());
					hayErrores = true;
				}
			}
			else{
				if(!hayErrores)errores.addError("Error: Fallo de estructura instruccion hacer ( - Linea: "+analisisLEx.getNumLinea());
				hayErrores = true;
			}
		}
		else{
			if(!hayErrores)errores.addError("Error: Fallo de estructura instruccion hacer  - Linea: "+analisisLEx.getNumLinea());
			hayErrores = true;
		}
		
	}
	
	/**
	 * ISI->(EXP) INSTRCOMP ELSE
	 * @throws Exception 
	 */
	private void ISI() throws Exception {
		if(tokenActual.getLexema().equals("(")){
			tokenActual = analisisLEx.analiza();
			EXP();
			int irf = traductor.traduce("ir_falso");
			if(tokenActual.getLexema().equals(")")){
				tokenActual = analisisLEx.analiza();
				INSTRCOMP();
				int ira = traductor.traduce("ir_a");
				traductor.parchea("ir_falso "+traductor.obtenerCodigoObjeto().size(), irf);
				ELSE();
				traductor.parchea("ir_a "+traductor.obtenerCodigoObjeto().size(), ira);
			}
			else{
				if(!hayErrores)errores.addError("Error: Fallo de estructura instruccion SI ) - Linea: "+analisisLEx.getNumLinea());
				hayErrores = true;
			}
		}
		else{
			if(!hayErrores)errores.addError("Error: Fallo de estructura instruccion SI ( - Linea: "+analisisLEx.getNumLinea());
			hayErrores = true;
		}
		
	}
	
	/**
	 * ELSE->sino INSTRCOMP 
	 * @throws Exception 
	 */
	private void ELSE() throws Exception {
		if(tokenActual.getLexema().equals("sino")){
			tokenActual = analisisLEx.analiza();
			INSTRCOMP();
		}
		
	}
	
	/**
	 * IMIENTRAS->(EXP)hacer INSTRCOMP
	 * @throws Exception 
	 */
	private void IMIENTRAS() throws Exception {
		if(tokenActual.getLexema().equals("(")){
			tokenActual = analisisLEx.analiza();
			int ira = traductor.obtenerCodigoObjeto().size();
			EXP();
			int irf = traductor.traduce("ir_falso");
			if(tokenActual.getLexema().equals(")")){
				
				tokenActual = analisisLEx.analiza();
				if(tokenActual.getLexema().equals("hacer")){
					tokenActual = analisisLEx.analiza();
					INSTRCOMP();
					traductor.traduce("ir_a "+ira);
					traductor.parchea("ir_falso "+traductor.obtenerCodigoObjeto().size(), irf);
				}
				else{
					if(!hayErrores)errores.addError("Error: Fallo de estructura instruccion mientras -hacer - Linea: "+analisisLEx.getNumLinea());
					hayErrores = true;
				}
			}
			else{
				if(!hayErrores)errores.addError("Error: Fallo de estructura instruccion mientras ) - Linea: "+analisisLEx.getNumLinea());
				hayErrores = true;
			}
		}
		else{
			if(!hayErrores)errores.addError("Error: Fallo de estructura instruccion mientras ( - Linea: "+analisisLEx.getNumLinea());
			hayErrores = true;
		}
		
	}
	
	/**
	 * IDECLATIPO->Identificador : TIPOCONSTRUIDO
	 * @throws Exception 
	 */
	private void IDECLATIPO() throws Exception {
		INodoEstructura nodo = null;
		if(tokenActual.getIdentificador() == 256){
			//Aqui establezco en la tabla de simbolos el nombre del tipo que declaro
			Token tAux =tokenActual;
			if(!tablaSymbol.estaToken(tokenActual.getLexema())){
				tokenActual = analisisLEx.analiza();
				if(tokenActual.getLexema().equals(":")){
					tokenActual = analisisLEx.analiza();
					nodo = TIPOCONSTRUIDO();
				}
				else
					if(!hayErrores)errores.addError("Error: Fallo de estructura. No se puede declarar el tipo - Linea: +analisisLEx.getNumLinea()");
				if(nodo != null)
					tablaSymbol.meteToken(tAux.getLexema(), tAux.getIdentificador(), ClaseToken.TIPO, nodo.getTipo(), nodo,nivel);
			}
			else{
				if(!hayErrores)errores.addError("Error. Restriccion contextual. Nombre de Tipo duplicado - Linea: "+analisisLEx.getNumLinea());
				hayErrores = true;
			}
		}
		else{
			if(!hayErrores)errores.addError("Error: Fallo de estructura. No se puede declarar el tipo - Linea: "+analisisLEx.getNumLinea());
			hayErrores = true;
		}
		
	}
	
	/**
	 * IDECLAVAR->TIPOCONSTRUIDO LISTAIDENT
	 * @throws Exception 
	 */
	private void IDECLAVAR() throws Exception {
		INodoEstructura nodo = TIPOCONSTRUIDO();
		LISTAIDENT(nodo);		
	}
	
	
	/**
	 * LISTAIDENT->Identificador RLISTAIDENT
	 * @throws Exception 
	 */
	private void LISTAIDENT(INodoEstructura nodo) throws Exception {
		if(tokenActual.getIdentificador() == 256){
			//aqui es donde meto los tokens que declaro??
			if(!tablaSymbol.estaToken(tokenActual.getLexema())){
				tablaSymbol.meteToken(tokenActual.getLexema(),tokenActual.getIdentificador(),ClaseToken.VARIABLE,nodo.getTipo(),nodo,nivel);
				tokenActual =  analisisLEx.analiza();
				RLISTAIDENT(nodo);
			}
			else{
				if(!hayErrores)errores.addError("Error. Restriccion contextual. Identificador ya usado - Linea: "+analisisLEx.getNumLinea());
				hayErrores = true;
				tokenActual =  analisisLEx.analiza();
				RLISTAIDENT(nodo);
			}
		}
		else{
			if(!hayErrores)errores.addError("Error. Fallo de estructura. Lista de identidficadores - Linea: "+analisisLEx.getNumLinea());
			hayErrores = true;
		}
		
	}
	
	/**
	 * 
	 * RLISTAIDENT->, LISTAIDENT | lambda -----------> es como si hiciera esto
	 * porq	 vuelve a hacer RLISTAIDENT->,Identificador RLISTAIDENT
	 * 
	 * @throws Exception 
	 */
	private void RLISTAIDENT(INodoEstructura nodo) throws Exception {
		if(tokenActual.getLexema().equals(",")){
			tokenActual =  analisisLEx.analiza();
			//aqui es donde meto los tokens que declaro??
			if(!tablaSymbol.estaToken(tokenActual.getLexema())){
				tablaSymbol.meteToken(tokenActual.getLexema(),tokenActual.getIdentificador(),ClaseToken.VARIABLE,nodo.getTipo(),nodo,nivel);
				tokenActual =analisisLEx.analiza();
				RLISTAIDENT(nodo);
			}
			else{
				if(!hayErrores)errores.addError("Error. Restriccion contextual. Variable duplicada - Linea: "+analisisLEx.getNumLinea());
				tokenActual =  analisisLEx.analiza();
				hayErrores = true;
				RLISTAIDENT(nodo);
			}
		}
		
	}
	/**
	 * 	TIPOCONSTRUIDO-> @ TIPOCONSTRUIDO
	 *	TIPOCONSTRUIDO-> registro Lcampos freg
	 *	TIPOCONSTRUIDO-> array Lrangos de TIPOCONSTRUIDO
	 *	TIPOCONSTRUIDO-> entero | real | bool
	 *  TIPOCONSTRUIDO-> Identificador (de Tipo)
	 * @throws Exception 
	 */
	private INodoEstructura TIPOCONSTRUIDO() throws Exception {
		if(tokenActual.getLexema().equals("@")){
			tokenActual = analisisLEx.analiza();
			INodoEstructura nodo = TIPOCONSTRUIDO();
			NodoPuntero punt = new NodoPuntero();
			punt.anade("", nodo);
			punt.setTipo(ClaseTipos.PUNTERO);
			return punt;
		}
		else if(tokenActual.getLexema().equals("registro")){
			tokenActual = analisisLEx.analiza();
			NodoRegistro regist = new NodoRegistro();
			LCAMPOS(regist);
			if(tokenActual.getLexema().equals("freg")){
				tokenActual = analisisLEx.analiza();
				regist.setTipo(ClaseTipos.REGISTRO);
				return regist;
			}
			else{
				if(!hayErrores)errores.addError("Error. Fallo de estructura. TIPO registro - Linea: "+analisisLEx.getNumLinea());
				hayErrores = true;
			}
		}
		else if(tokenActual.getLexema().equals("array")){
			tokenActual = analisisLEx.analiza();
			NodoArray array = new NodoArray();
			int i = LRANGOS();
			if(tokenActual.getLexema().equals("de")){
				tokenActual = analisisLEx.analiza();
				INodoEstructura nodo = TIPOCONSTRUIDO();
				if(i > 0){ //i= longitud del array unidimensional. 
					for(int j = 0; j < i;j++)
						array.anade(j+"", nodo);
				}else{
					if(!hayErrores)errores.addError("Error. Fallo de estructura.Longitud. TIPO array - Linea: "+analisisLEx.getNumLinea());
					hayErrores = true;
				}
				array.setTipo(ClaseTipos.ARRAY);
				return array;
			}
			else{
				if(!hayErrores)errores.addError("Error. Fallo de estructura. TIPO array - Linea: "+analisisLEx.getNumLinea());
				hayErrores = true;
			}
		}
		else if(palReservTipos.esReservada(tokenActual.getLexema())){
			NodoBasico basic = new NodoBasico();
			if(tokenActual.getLexema().equals("ent"))
				basic.setTipo(ClaseTipos.ENT);
			else if(tokenActual.getLexema().equals("real"))
				basic.setTipo(ClaseTipos.REAL);
			else if(tokenActual.getLexema().equals("bool"))
				basic.setTipo(ClaseTipos.BOOLEAN);
			tokenActual = analisisLEx.analiza();
			return basic;
		}
		else if(tablaSymbol.esTipo(tokenActual.getLexema())){
			INodoEstructura nodo =tablaSymbol.dameEstructura(tokenActual.getLexema());
			tokenActual = analisisLEx.analiza();
			return nodo;
		}
		else{
			if(!hayErrores)errores.addError("Error. Restriccion contextual. NO existe el tipo - Linea: "+analisisLEx.getNumLinea());
			hayErrores = true;
		}
		return null;
	}
	

	/**
	 * LCAMPOS->Identificador: TIPOCONSTRUIDO RLCAMPOS | lambda
	 * El registro puede estar vacio; sin campos. �Bien?
	 * @throws Exception 
	 */
	private void LCAMPOS(NodoRegistro regist) throws Exception {
		if(tokenActual.getIdentificador() == 256 && !tokenActual.getLexema().equals("freg")){
			//identificador del campo del registro
			Token tIdCampo = tokenActual;
			tokenActual = analisisLEx.analiza();
			if(tokenActual.getLexema().equals(":")){
				tokenActual = analisisLEx.analiza();
				INodoEstructura nodo = TIPOCONSTRUIDO();
				if(nodo != null)
				if(regist.anade(tIdCampo.getLexema(), nodo))
					RLCAMPOS(regist);
				else{
					if(!hayErrores)errores.addError("Error. Restriccion contextual. Dos campos con el mismo nombre - Linea: "+analisisLEx.getNumLinea());
					hayErrores = true;
				}
			}
			else{
				if(!hayErrores)errores.addError("Error: Fallo de estructura - Linea: "+analisisLEx.getNumLinea());
				hayErrores = true;
			}
		}
		
	}
	
	/**
	 * RLCAMPOS->; LCAMPOS | lambda
	 * El ultimo campo del registro no tiene obligacion de acabar con Punto y coma
	 * @throws Exception 
	 */
	private void RLCAMPOS(NodoRegistro regist) throws Exception {
		if(tokenActual.getLexema().equals(";")){
			tokenActual = analisisLEx.analiza();
			LCAMPOS(regist);
		}
		
	}
	
	/**
	 * IASIGVAR->= EXP
	 * @throws Exception 
	 */
	private INodoEstructura IASIGVAR() throws Exception {
		if(tokenActual.getLexema().equals("=")){
			tokenActual = analisisLEx.analiza();
			//ahora asignara una expresion a la variable
			INodoEstructura nodo= EXP();
			return nodo;
		}
		else{
			if(!hayErrores)errores.addError("Error: Fallo de estructura. No se puede asignar la variable - Linea: "+analisisLEx.getNumLinea());
			hayErrores = true;
			return null;
		}
	}
	
	/**
	 *EXP-> EXPSIMPLE REXP
	 * @throws Exception 
	 */
	private INodoEstructura EXP() throws Exception {
		INodoEstructura nodo1 = EXPSIMPLE();
		INodoEstructura nodo2 = REXP();
		if(nodo1 != null && nodo2 != null)
			if(!ComprobacionTipos.compruebaCompatibilidad(nodo1, nodo2)){
				if(!hayErrores)errores.addError("Error: Incompatibilidad de tipos - Linea: "+analisisLEx.getNumLinea());
				hayErrores = true;
			}
		if(nodo1 == null)
			return nodo2;
		else
			return nodo1;
	}
	
	
	/**
	 *REXP -> == EXPSIMPLE
	 *REXP -> <> EXPSIMPLE
	 *REXP -> <  EXPSIMPLE
	 *REXP -> >= EXPSIMPLE
	 *REXP -> >  EXPSIMPLE
	 *REXP -> <= EXPSIMPLE
	 *
	 *Corresponde con lo de la documentacion:
	 *REXP -> OpRel EXPSIMPLE
	 *Oprel-> == | <> | < | >= | > | <=
	 * @throws Exception 
	 */
	private INodoEstructura REXP() throws Exception {
		if(tokenActual.getLexema().equals("==")){
			tokenActual = analisisLEx.analiza();
			INodoEstructura nodo = EXPSIMPLE();
			traductor.traduce("igual");
			return nodo;
		}
		else if(tokenActual.getLexema().equals("<>")){
			tokenActual = analisisLEx.analiza();
			INodoEstructura nodo = EXPSIMPLE();
			traductor.traduce("distinto");
			return nodo;
		}
		else if(tokenActual.getLexema().equals("<")){
			tokenActual = analisisLEx.analiza();
			INodoEstructura nodo = EXPSIMPLE();
			traductor.traduce("menor");
			return nodo;
		}
		else if(tokenActual.getLexema().equals(">=")){
			tokenActual = analisisLEx.analiza();
			INodoEstructura nodo = EXPSIMPLE();
			traductor.traduce("mayorOIgual");
			return nodo;
		}
		else if(tokenActual.getLexema().equals(">")){
			tokenActual = analisisLEx.analiza();
			INodoEstructura nodo = EXPSIMPLE();
			traductor.traduce("mayor");
			return nodo;
		}
		else if(tokenActual.getLexema().equals("<=")){
			tokenActual = analisisLEx.analiza();
			INodoEstructura nodo = EXPSIMPLE();
			traductor.traduce("menorOIgual");
			return nodo;
		}
		return null;
	}
	
	
	
	/**
	 *EXPSIMPLE --> TERM REXPSIMPLE
	 * @throws Exception 
	 */
	private INodoEstructura EXPSIMPLE() throws Exception {
		INodoEstructura nodo1 = TERM();
		INodoEstructura nodo2 = REXPSIMPLE();
		if(nodo1 != null && nodo2 != null)
			if(!ComprobacionTipos.compruebaCompatibilidad(nodo1, nodo2)){
				if(!hayErrores)errores.addError("Error: Incompatibilidad de tipos - Linea: "+analisisLEx.getNumLinea());
				hayErrores = true;
			}
		if(nodo1 == null)
			return nodo2;
		else
			return nodo1;
	}
	
	
	/**
	 *REXPSIMPLE -> + EXPSIMPLE
	 *REXPSIMPLE -> - EXPSIMPLE
	 *REXPSIMPLE -> or EXPSIMPLE
	 *REXPSIMPLE -> lambda
	 *Corresponde con lo de la documentacion:
	 *REXPSIMPLE -> OpAd TERM REXPSIMPLE (q es = que )REXPSIMPLE -> OpAd EXPSIMPLE
	 *OpAd -> + | - | or
	 * @throws Exception 
	 */
	private INodoEstructura REXPSIMPLE() throws Exception {
		if(tokenActual.getLexema().equals("+")){
			tokenActual = analisisLEx.analiza();
			INodoEstructura nodo = EXPSIMPLE();
			traductor.traduce("suma");
			return nodo;
		}
		else if(tokenActual.getLexema().equals("-")){
			tokenActual = analisisLEx.analiza();
			INodoEstructura nodo = EXPSIMPLE();
			traductor.traduce("resta");
			return nodo;
		}
		else if(tokenActual.getLexema().equals("or")){
			tokenActual = analisisLEx.analiza();
			INodoEstructura nodo = EXPSIMPLE();
			traductor.traduce("or");
			return nodo;
		}
		return null;
	}
	
	
	/**
	 *TERM --> FACT RTERM 
	 * @throws Exception 
	 */
	private INodoEstructura TERM() throws Exception {
		INodoEstructura nodo1 = FACT();
		INodoEstructura nodo2 = RTERM();
		if(nodo1 != null && nodo2 != null)
			if(!ComprobacionTipos.compruebaCompatibilidad(nodo1, nodo2)){
				if(!hayErrores)errores.addError("Error: Incompatibilidad de tipos - Linea: "+analisisLEx.getNumLinea());
				hayErrores = true;
			}
		if(nodo1 == null)
			return nodo2;
		else
			return nodo1;
		
	}
	
	/**
	 *RTERM --> * TERM
	 *RTERM --> / TERM
	 *RTERM --> % TERM
	 *RTERM --> and TERM
	 *Corresponde con lo de la documentacion:
	 *RETERM -> OpMul FACT RTERM(q es = que )RETERM -> OpMul TERM
	 *OpMul -> * | / | % | and
	 * @throws Exception 
	 */
	private INodoEstructura RTERM() throws Exception {
		if(tokenActual.getLexema().equals("*")){
			tokenActual = analisisLEx.analiza();
			INodoEstructura nodo = TERM();
			traductor.traduce("multiplica");
			return nodo;
		}
		else if(tokenActual.getLexema().equals("/")){
			tokenActual = analisisLEx.analiza();
			INodoEstructura nodo = TERM();
			traductor.traduce("divide");
			return nodo;
		}
		else if(tokenActual.getLexema().equals("%")){
			tokenActual = analisisLEx.analiza();
			INodoEstructura nodo = TERM();
			traductor.traduce("mod");
			return nodo;
		}
		else if(tokenActual.getLexema().equals("and")){
			tokenActual = analisisLEx.analiza();
			INodoEstructura nodo = TERM();
			traductor.traduce("and");
			return nodo;
		}
		return null;
	}

	/**
	 *FACT -> true | false | (EXP) | DESCRIPT | enteros | reales |OPUNFACT
	 *FACT -> identDeFuncion (LISTPARAMETROS)
	 * 
	 * Devuelve un entero
	 * @throws Exception 
	 */
	private INodoEstructura FACT() throws Exception {
		if(tokenActual.getLexema().equals("true")){
			traductor.traduce("apila 0");
			tokenActual = analisisLEx.analiza();
			INodoEstructura nodo = new NodoBasico();
			nodo.setTipo(ClaseTipos.BOOLEAN);
			return nodo;
		}
		else if(tokenActual.getLexema().equals("false")){
			traductor.traduce("apila -1");
			tokenActual = analisisLEx.analiza();
			INodoEstructura nodo = new NodoBasico();
			nodo.setTipo(ClaseTipos.BOOLEAN);
			return nodo;
		}
		else if(tokenActual.getLexema().equals("(")){
			tokenActual = analisisLEx.analiza();
			INodoEstructura nodo =  EXP();
			if(tokenActual.getLexema().equals(")")){
				tokenActual = analisisLEx.analiza();				
			}
			else{
				if(!hayErrores)errores.addError("Error: Fallo de estructura. En la expresion - Linea: "+analisisLEx.getNumLinea());
				hayErrores = true;
			}
			return nodo;
		}
		else if(tablaSymbol.esFuncion(tokenActual.getLexema())){
			Token nomf = tokenActual;
			tokenActual = analisisLEx.analiza();
			if(tokenActual.getLexema().equals("(")){
				PASOPARAMETROS();
				if(!tokenActual.getLexema().equals(")")){
					if(!hayErrores)errores.addError("Error: Fallo de estructura. En la expresion - Linea: "+analisisLEx.getNumLinea());
					hayErrores = true;
				}
				traductor.traduce("incrementa 1");//+(tablaSymbol.dameEstructura(nomf.getLexema()).getOffset()+1));
				traductor.traduce("llama "+tablaSymbol.dirMemoriaToken(nomf)+" "+tablaSymbol.nivel(nomf.getLexema()));
				tokenActual = analisisLEx.analiza();
				INodoEstructura nAux = new NodoBasico();
				ClaseTipos c = tablaSymbol.dameTipo(nomf.getLexema()); 
				nAux.setTipo(c);
				return nAux;
			}
			else{
				if(!hayErrores)errores.addError("Error: Fallo de estructura. En la expresion - Linea: "+analisisLEx.getNumLinea());
				hayErrores = true;
			}
		}
		else if(tokenActual.getIdentificador() == 256){ //Identificadores
			if(tablaSymbol.estaToken(tokenActual.getLexema()) && tablaSymbol.esVariable(tokenActual.getLexema())){	
				INodoEstructura nodo = DESCRIPT();
				traductor.traduce("apila_ind");
				return nodo;
			}
			else if(estoyEnFuncion){
				if(((NodoParametros)tablaSymbol.dameEstructura(nombreFuncion)).perteneceCampo(tokenActual.getLexema())){
					int posPar = ((NodoParametros)tablaSymbol.dameEstructura(nombreFuncion)).getOffset() - ((NodoParametros)tablaSymbol.dameEstructura(nombreFuncion)).posicionCampo(tokenActual.getLexema());
					traductor.traduce("apila -"+(posPar+1));
					traductor.traduce("apila "+nivel);
					traductor.traduce("apila_ind");
					tokenActual =  analisisLEx.analiza();
				}
				else{
					if(!hayErrores)errores.addError("Error. Restriccion contextual. No existe la variable - Linea: "+analisisLEx.getNumLinea());
					hayErrores = true;
				}
			}
			else{
				if(!hayErrores)errores.addError("Error. Restriccion contextual. No existe la variable - Linea: "+analisisLEx.getNumLinea());
				hayErrores = true;
			}
		}
		else if(tokenActual.getIdentificador() == 257){ //Enteros
			Token num = tokenActual;
			traductor.traduce("apila "+ ((int)num.getValor()));
			tokenActual = analisisLEx.analiza();
			INodoEstructura nodo = new NodoBasico();
			nodo.setTipo(ClaseTipos.ENT);
			return nodo;
		}
		else if(tokenActual.getIdentificador() == 258){//reales
			Token num = tokenActual;
			tokenActual = analisisLEx.analiza();
			traductor.traduce("apila "+((double)num.getValor()));
			INodoEstructura nodo = new NodoBasico();
			nodo.setTipo(ClaseTipos.REAL);
			return nodo;
		}
		else
			OPUNFACT();
		return null;
		
	}
	
	
	
	/**
	 *LRANGOS--> [ entero ] 
	 * @throws Exception 
	 */
	private int LRANGOS() throws Exception {
		int i = 0;
		if(tokenActual.getLexema().equals("[")){
			tokenActual = analisisLEx.analiza();
			if(tokenActual.getIdentificador() == 257){ //Enteros
				Token num = tokenActual;
				tokenActual = analisisLEx.analiza();
				i = (int)num.getValor();
			}
			if(tokenActual.getLexema().equals("]")){
				tokenActual = analisisLEx.analiza();
			}
			else{
				if(!hayErrores)errores.addError("Error: Fallo de estructura. Declaracion de rangos - Linea: "+analisisLEx.getNumLinea());
				hayErrores = true;
			}
			return i;
		}
		else{
			if(!hayErrores)errores.addError("Error: Fallo de estructura. Declaracion de rangos - Linea: "+analisisLEx.getNumLinea());
			hayErrores = true;
			return -1;
		}
		
	}
		
	/**
	 *OPUNFACT--> - FACT | + FACT
	 * @throws Exception 
	 */
	private void OPUNFACT() throws Exception {
		if(tokenActual.getLexema().equals("-")){
			tokenActual = analisisLEx.analiza();
			traductor.traduce("apila 0");
			FACT();
			traductor.traduce("resta");
		}
		else if(tokenActual.getLexema().equals("+")){
			tokenActual = analisisLEx.analiza();
			traductor.traduce("apila 0");
			FACT();
			traductor.traduce("suma");
		}
		
	}
	
	/**
	 *DESCRIPT-> Identificador RDESCRIPT
	 * @throws Exception 
	 */
	private INodoEstructura DESCRIPT() throws Exception {
		if(tokenActual.getIdentificador() == 256){
			Token raiz = tokenActual;
			tokenActual = analisisLEx.analiza();
			INodoEstructura nodo;
			if(tablaSymbol.dameEstructura(raiz.getLexema()).getTipo() == ClaseTipos.PUNTERO){
				nodo = RDESCRIPT(tablaSymbol.dameEstructura(raiz.getLexema()), tablaSymbol.dirMemoriaToken(raiz));
				traductor.traduce("desapila");
				traductor.traduce("apila "+tablaSymbol.dirMemoriaToken(raiz));
				traductor.traduce("apila "+tablaSymbol.nivel(raiz.getLexema()));
				traductor.traduce("apila_ind");
			}
			else
				nodo = RDESCRIPT(tablaSymbol.dameEstructura(raiz.getLexema()), tablaSymbol.dirMemoriaToken(raiz));
			traductor.traduce("apila "+tablaSymbol.nivel(raiz.getLexema()));
			return nodo;
		}
		else
			return null;
	}
	/**
	 *RDESCRIPT -> @ RDESCRIPT | .RDESCRIPT | LRANGOS RDESCRIPT
	 *
	 * @throws Exception 
	 */
	private INodoEstructura RDESCRIPT(INodoEstructura nodo, int dirCamp) throws Exception {
		if(nodo.getTipo() == ClaseTipos.ENT || nodo.getTipo() == ClaseTipos.REAL ||nodo.getTipo() == ClaseTipos.BOOLEAN){
			traductor.traduce("apila "+dirCamp);
			return nodo;
		}
		else			
			try{
				if(tokenActual.getLexema().equals("@")){
					tokenActual = analisisLEx.analiza();
					INodoEstructura nodoP = RDESCRIPT(((NodoPuntero)nodo).getEstructuraPuntero(),dirCamp);
					return nodoP;
				}
				else if(tokenActual.getLexema().equals(".")){
					tokenActual = analisisLEx.analiza();
					NodoRegistro nodoReg = (NodoRegistro) nodo;
					String campo = tokenActual.getLexema();
					if(nodoReg.perteneceCampo(tokenActual.getLexema())){
						//Cojo el siguiente punto...
						Token tCamp = tokenActual;
						tokenActual = analisisLEx.analiza();
						INodoEstructura nodoR = RDESCRIPT(nodoReg.getEstructuraCampo(tCamp.getLexema()),dirCamp+nodoReg.posicionCampo(campo));
						return nodoR;
					}
					else{
						errores.addError("Error. ");
						hayErrores = true;
					}
				}
				else if(tokenActual.getLexema().equals("[")){
					int i = LRANGOS();
					if(i >= 0){
						INodoEstructura nodoA = RDESCRIPT(((NodoArray)nodo).getEstructuraCampo(i+""),dirCamp+((NodoArray)nodo).posicionCampo(i+""));
						return nodoA;
					}
					else{
						if(!hayErrores)errores.addError("Error indice vector ");
						hayErrores =true;
					}
				}
			}catch(ClassCastException e){
				if(!hayErrores)errores.addError("Error: Fallo de uso de tipos - Linea: "+analisisLEx.getNumLinea());
				hayErrores = true;
			}
		return nodo;
	}
	
	
}
